package LAAMI;

import repast.simphony.engine.environment.RunEnvironment;
import repast.simphony.engine.schedule.ScheduledMethod;

import org.apache.commons.math.stat.descriptive.DescriptiveStatistics;

public class Investor {
	// histVolatility is the subjective estimation of the agent about the
	// historical volatility. It is the standard deviation of the daily
	// of the stock prices for an observation window of patience days in
	// the past multiplied (shifted) by judgment.
	private double histVolatility;
	// Patience is the minimum length of days to calculate historical
	// volatility, which is given by a random integer between 5 and 45 (days).
	private int patience;
	// Judgment is the trader’s personal adjustment of his experience in
	// historical volatility band, which is given by a random number between
	// 0.5 and 1.5 at the beginning of simulation and remains constant.
	private double judgement;
	// Call price is the price in which an investor is willing to sell.
	private double callPrice;
	// Ask price is the price in which an investor is willing to buy.
	private double askPrice;
	// We specify a band of volatility for each agent with minVolatility
	// being the lower bound and maxVolatility the upper bound
	private double minVolatility;
	private double maxVolatility;
	private double money;
	private int optionNo;
	private double profit;

	public Investor(int patience, double judgement) {
		setPatience(patience);
		setJudgement(judgement);
		setMaxVolatility(Double.MIN_VALUE);
		setMinVolatility(Double.MAX_VALUE);
		setMoney(0);
		setOptionNo(0);
	}

	// After patience days, agents make their estimation for the historical
	// volatility, they construct their volatility band and set the range
	// of prices they are willing to trade.
	@ScheduledMethod(start = 1, interval = 1, priority = 2)
	public void step() {
		int curDay = (int) RunEnvironment.getInstance().getCurrentSchedule()
				.getTickCount();
		if (curDay > patience && curDay <= LAAMIBuilder.getExpDay()) {
			estimHistVol();
			updateVolBand();
			if (curDay >= 50) {
				updatePriceRange();
			}
		}
	}

	@ScheduledMethod(start = 51, interval = 1, priority = 4)
	public void trade() {
		int curDay = (int) RunEnvironment.getInstance().getCurrentSchedule()
				.getTickCount();
		if (curDay <= LAAMIBuilder.getExpDay()) {
			if (LAAMIBuilder.getOptionmarket().getPrice() < askPrice)
				buy();
			else if (LAAMIBuilder.getOptionmarket().getPrice() > callPrice)
				sell();
			setProfit(calcProfit());
		}
	}

	// For a range of "patience" days in the past, agents take as historical
	// volatility the standard deviation of the daily change of prices
	// and then they multiply that by judgment.
	public void estimHistVol() {
		DescriptiveStatistics Stats = new DescriptiveStatistics();
		int curDay = (int) RunEnvironment.getInstance().getCurrentSchedule()
				.getTickCount();
		for (int i = 1; i < patience; i++) {
			double priceNew = (Double) LAAMIBuilder.getStockmarket().priceList
					.get(curDay - i);
			double priceOld = (Double) LAAMIBuilder.getStockmarket().priceList
					.get(curDay - (i + 1));

			double dailyChange = (double) (priceNew - priceOld) / priceOld;
			Stats.addValue(dailyChange);
		}
		double StdDev = Stats.getStandardDeviation();
		double histVol = (double) (StdDev * judgement);
		setHistVolatility(histVol);
	}

	// Update minimum and maximum volatility values
	public void updateVolBand() {
		if (histVolatility > maxVolatility)
			setMaxVolatility(histVolatility);
		if (histVolatility < minVolatility)
			setMinVolatility(histVolatility);
	}

	// We use the BlackScholes formula with the current price of the underlying
	// stock market, the strike price, the maturity, the interest rate, drift
	// and maximum volatility to find the upper bound of the agent's price
	// range.
	// We use the BlackScholes formula with the current price of the underlying
	// stock market, the strike price, the maturity, the interest rate, drift
	// and minimum volatility to find the lower bound of the agent's price
	// range.
	public void updatePriceRange() {
		setCallPrice(BlackScholes.getPrice(maxVolatility));
		setAskPrice(BlackScholes.getPrice(minVolatility));
	}

	public void buy() {
		double optPrice = LAAMIBuilder.getOptionmarket().getPrice();
		setOptionNo(getOptionNo() + 1);
		setMoney(money - optPrice);
	}

	public void sell() {
		double optPrice = LAAMIBuilder.getOptionmarket().getPrice();
		setOptionNo(getOptionNo() - 1);
		setMoney(money + optPrice);

	}

	public double calcProfit() {
		double optPrice = LAAMIBuilder.getOptionmarket().getPrice();
		return optionNo * optPrice + getMoney();
	}

	/*-------------setters/getters--------------------*/

	public double getHistVolatility() {
		return histVolatility;
	}

	public void setHistVolatility(double histVolatility) {
		this.histVolatility = histVolatility;
	}

	public int getPatience() {
		return patience;
	}

	public void setPatience(int patience) {
		this.patience = patience;
	}

	public double getJudgement() {
		return judgement;
	}

	public void setJudgement(double judgement) {
		this.judgement = judgement;
	}

	public double getCallPrice() {
		return callPrice;
	}

	public void setCallPrice(double callPrice) {
		this.callPrice = callPrice;
	}

	public double getAskPrice() {
		return askPrice;
	}

	public void setAskPrice(double askPrice) {
		this.askPrice = askPrice;
	}

	public double getMinVolatility() {
		return minVolatility;
	}

	public void setMinVolatility(double minVolatility) {
		this.minVolatility = minVolatility;
	}

	public double getMaxVolatility() {
		return maxVolatility;
	}

	public void setMaxVolatility(double maxVolatility) {
		this.maxVolatility = maxVolatility;
	}

	public double getMoney() {
		return money;
	}

	public void setMoney(double money) {
		this.money = money;
	}

	public int getOptionNo() {
		return optionNo;
	}

	public void setOptionNo(int optionNo) {
		this.optionNo = optionNo;
	}

	public double getProfit() {
		return profit;
	}

	public void setProfit(double profit) {
		this.profit = profit;
	}
}
